package com.zhaokuner.plugins.gettersettertostring.action.handler;

import com.intellij.codeInsight.generation.PsiElementClassMember;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiPackage;
import com.zhaokuner.plugins.gettersettertostring.factory.CreateBuilderDialogFactory;
import com.zhaokuner.plugins.gettersettertostring.factory.MemberChooserDialogFactory;
import com.zhaokuner.plugins.gettersettertostring.factory.PsiFieldsForBuilderFactory;
import com.zhaokuner.plugins.gettersettertostring.gui.CreateBuilderDialog;
import com.zhaokuner.plugins.gettersettertostring.psi.PsiFieldSelector;
import com.zhaokuner.plugins.gettersettertostring.psi.PsiHelper;
import com.zhaokuner.plugins.gettersettertostring.psi.model.PsiFieldsForBuilder;
import com.zhaokuner.plugins.gettersettertostring.writer.BuilderContext;
import com.zhaokuner.plugins.gettersettertostring.writer.BuilderWriter;

import java.util.List;

public class DisplayChoosers {

    private PsiClass psiClassFromEditor;
    private Project project;
    private Editor editor;
    private PsiHelper psiHelper;
    private CreateBuilderDialogFactory createBuilderDialogFactory;
    private PsiFieldSelector psiFieldSelector;
    private MemberChooserDialogFactory memberChooserDialogFactory;
    private BuilderWriter builderWriter;
    private PsiFieldsForBuilderFactory psiFieldsForBuilderFactory;

    public DisplayChoosers(PsiHelper psiHelper, CreateBuilderDialogFactory createBuilderDialogFactory,
                           PsiFieldSelector psiFieldSelector, MemberChooserDialogFactory memberChooserDialogFactory,
                           BuilderWriter builderWriter, PsiFieldsForBuilderFactory psiFieldsForBuilderFactory) {
        this.psiHelper = psiHelper;
        this.createBuilderDialogFactory = createBuilderDialogFactory;
        this.psiFieldSelector = psiFieldSelector;
        this.memberChooserDialogFactory = memberChooserDialogFactory;
        this.builderWriter = builderWriter;
        this.psiFieldsForBuilderFactory = psiFieldsForBuilderFactory;
    }

    @SuppressWarnings("rawtypes")
    public void run(PsiClass existingBuilder) {
        existingBuilder = null;
        CreateBuilderDialog createBuilderDialog = null;
        PsiDirectory targetDirectory = psiHelper.getPsiFileFromEditor(editor, project).getContainingDirectory();
        String className = psiClassFromEditor.getName();
        String methodPrefix = "_";
        boolean innerBuilder = true;
        boolean useSingleField = false;
        boolean hasButMethod = false;
        List<PsiElementClassMember> fieldsToDisplay = getFieldsToIncludeInBuilder(psiClassFromEditor, innerBuilder, useSingleField, hasButMethod);
        com.intellij.ide.util.MemberChooser<PsiElementClassMember> memberChooserDialog = memberChooserDialogFactory.getMemberChooserDialog(fieldsToDisplay, project);
        memberChooserDialog.show();
        myWriteBuilderIfNecessary(targetDirectory, className, methodPrefix, memberChooserDialog, createBuilderDialog, existingBuilder);
    }

    @SuppressWarnings("rawtypes")
    private void myWriteBuilderIfNecessary(
            PsiDirectory targetDirectory, String className, String
            methodPrefix, com.intellij.ide.util.MemberChooser<PsiElementClassMember> memberChooserDialog, CreateBuilderDialog
                    createBuilderDialog, PsiClass existingBuilder) {
        boolean innerBuilder = true;
        boolean useSingleField = false;
        boolean hasButMethod = false;

        List<PsiElementClassMember> selectedElements = memberChooserDialog.getSelectedElements();
        if (null == selectedElements || selectedElements.isEmpty()) {
            //啥都不做
            return;
        }
        PsiFieldsForBuilder psiFieldsForBuilder = psiFieldsForBuilderFactory.createPsiFieldsForBuilder(selectedElements, psiClassFromEditor);
        BuilderContext context = new BuilderContext(
                project, psiFieldsForBuilder, targetDirectory, className, psiClassFromEditor, methodPrefix, innerBuilder, hasButMethod, useSingleField);
        builderWriter.writeBuilder(context, existingBuilder);
    }

    @SuppressWarnings("rawtypes")
    private void writeBuilderIfNecessary(
            PsiDirectory targetDirectory, String className, String
            methodPrefix, com.intellij.ide.util.MemberChooser<PsiElementClassMember> memberChooserDialog, CreateBuilderDialog
                    createBuilderDialog, PsiClass existingBuilder) {
        if (memberChooserDialog.isOK()) {
            List<PsiElementClassMember> selectedElements = memberChooserDialog.getSelectedElements();
            PsiFieldsForBuilder psiFieldsForBuilder = psiFieldsForBuilderFactory.createPsiFieldsForBuilder(selectedElements, psiClassFromEditor);
            BuilderContext context = new BuilderContext(
                    project, psiFieldsForBuilder, targetDirectory, className, psiClassFromEditor, methodPrefix, createBuilderDialog.isInnerBuilder(), createBuilderDialog.hasButMethod(), createBuilderDialog.useSingleField());
            builderWriter.writeBuilder(context, existingBuilder);
        }
    }

    private CreateBuilderDialog showDialog(PsiClass existingBuilder) {
        PsiDirectory srcDir = psiHelper.getPsiFileFromEditor(editor, project).getContainingDirectory();
        PsiPackage srcPackage = psiHelper.getPackage(srcDir);
        CreateBuilderDialog dialog = createBuilderDialogFactory.createBuilderDialog(psiClassFromEditor, project, srcPackage, existingBuilder);
        dialog.show();
        return dialog;
    }

    @SuppressWarnings("rawtypes")
    private List<PsiElementClassMember> getFieldsToIncludeInBuilder(PsiClass clazz, boolean innerBuilder,
                                                                    boolean useSingleField, boolean hasButMethod) {
        return psiFieldSelector.selectFieldsToIncludeInBuilder(clazz, innerBuilder, useSingleField, hasButMethod);
    }

    public void setPsiClassFromEditor(PsiClass psiClassFromEditor) {
        this.psiClassFromEditor = psiClassFromEditor;
    }

    public void setProject(Project project) {
        this.project = project;
    }

    public void setEditor(Editor editor) {
        this.editor = editor;
    }
}
